package de.karlNet.sambamanager.view.beans.trees;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.annotation.PostConstruct;

import org.primefaces.event.NodeExpandEvent;
import org.primefaces.event.NodeSelectEvent;
import org.primefaces.model.DefaultTreeNode;
import org.primefaces.model.TreeNode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import de.karlNet.sambamanager.ldapController.ILdapTree;
import de.karlNet.sambamanager.ldapController.commands.FindFSMORoles;
import de.karlNet.sambamanager.ldapModel.ITypeCheckerCallback;
import de.karlNet.sambamanager.ldapModel.LdapDomainController;
import de.karlNet.sambamanager.ldapModel.LdapObject;
import de.karlNet.sambamanager.view.beans.DnsCNameBean;
import de.karlNet.sambamanager.view.beans.DnsRecordBean;
import de.karlNet.sambamanager.view.beans.DomainControllerDetailsBean;
import de.karlNet.sambamanager.view.beans.GroupDetailsBean;
import de.karlNet.sambamanager.view.beans.ManualLeafHandlingTreeNode;
import de.karlNet.sambamanager.view.beans.UserDetailsBean;

public abstract class AbstractTreeBean {

	@Value("${ldap.dnsName}")
	protected String dnsName;
	
	private String searchTerm;
	@Autowired
	private LdapMemberOfBean ldapMemberOfBean;

	@Autowired
	private LdapMemberBean ldapMemberBean;

	protected TreeNode root;
	@Autowired
	protected SelectedNodeContainer selectedNodeContainer;
	@Autowired
	private UserDetailsBean userDetailsBean;
	@Autowired
	private GroupDetailsBean groupDetailsBean;
	@Autowired
	private DomainControllerDetailsBean domainControllerDetailsBean;
	@Autowired
	private DnsRecordBean dnsRecordBean;
	@Autowired
	private DnsCNameBean dnsCNameBean;
	
	@Autowired
	private FindFSMORoles findFSMORoles;
	protected DefaultTreeNode myRoot;
	public AbstractTreeBean() {
		super();

	}
	
	protected void doTypeCallbacking() {
		this.selectedNodeContainer.selectedNode.getLdapObject().isType(
				new ITypeCheckerCallback() {
					public void isContainer() {
						groupDetailsBean.setShow(false);
					}

					@Override
					public void isGroup() {
						groupDetailsBean.setShow(true);
					}

					@Override
					public void isLdapDomainController(LdapDomainController ldapDomainController) {
						findFSMORoles.findFSMORolesItSelf(ldapDomainController);
						domainControllerDetailsBean.setShow(true);
					}
					
					@Override
					public void isUser() {
						userDetailsBean.setShow(true);
					}
					
					@Override
					public void isLdapDNSARecord() {
						dnsRecordBean.setShow(true);
					}
					
					@Override
					public void isLdapDNSCName() {
						dnsCNameBean.setShow(true);
					}
				});
	}
	
	public void expandAll() {
		this.removeNodes((ManualLeafHandlingTreeNode) this.myRoot);
		this.myRoot.setExpanded(true);
		this.expandAll((ManualLeafHandlingTreeNode) this.myRoot);
	}

	public void expandAll(ManualLeafHandlingTreeNode parent) {
		Iterator<TreeNode> i = this.gahterChildrenOfTreeNode(parent).iterator();
		while (i.hasNext()) {
			ManualLeafHandlingTreeNode child = (ManualLeafHandlingTreeNode) i
					.next();
			child.setExpanded(true);
			this.expandAll(child);
		}
	}
	
	public void expandSelected() {
		this.removeNodes(this.selectedNodeContainer.selectedNode);
		this.expandAll(this.selectedNodeContainer.selectedNode);
		this.selectedNodeContainer.selectedNode.setExpanded(true);
	}

	private List<TreeNode> gahterChildrenOfTreeNode(
			final ManualLeafHandlingTreeNode parent) {
		final List<TreeNode> children = new ArrayList<TreeNode>();
		for (final LdapObject ldapObject : this.getLdapTree().getChildrenOfDN(
				parent.getLdapObject().getDn())) {
			ldapObject.isType(new ITypeCheckerCallback() {

				public void isContainer() {
					ManualLeafHandlingTreeNode child = new ManualLeafHandlingTreeNode(
							"container", ldapObject, parent);
					children.add(child);
				}

				public void isGroup() {
					ManualLeafHandlingTreeNode child = new ManualLeafHandlingTreeNode(
							"group", ldapObject, parent);
					children.add(child);
				}

				@Override
				public void isLdapDNSARecord() {
					ManualLeafHandlingTreeNode child = new ManualLeafHandlingTreeNode(
							"ldapDNSARecord", ldapObject, parent);
					children.add(child);
				}
				
				@Override
				public void isLdapDNSCName() {
					ManualLeafHandlingTreeNode child = new ManualLeafHandlingTreeNode(
							"ldapDNSCName", ldapObject, parent);
					children.add(child);
				}

				@Override
				public void isLdapDNSZone() {
					ManualLeafHandlingTreeNode child = new ManualLeafHandlingTreeNode(
							"ldapDNSZone", ldapObject, parent);
					children.add(child);
				}

				@Override
				public void isLdapDomainController() {
					ManualLeafHandlingTreeNode child = new ManualLeafHandlingTreeNode(
							"domainController", ldapObject, parent);
					children.add(child);
				}
				
				@Override
				public void isLdapObject() {
					ManualLeafHandlingTreeNode child = new ManualLeafHandlingTreeNode(
							"ldapObject", ldapObject, parent);
					children.add(child);
				}
				
				public void isNestable() {

				}
				
				public void isUser() {
					ManualLeafHandlingTreeNode child = new ManualLeafHandlingTreeNode(
							"user", ldapObject, parent);
					children.add(child);
				}
			});

		}
		return children;
	}

	protected abstract ILdapTree getLdapTree();

	public TreeNode getRoot() {
		return root;
	}

	public String getSearchTerm() {
		return searchTerm;
	}

	public TreeNode getSelectedNode() {
		return this.selectedNodeContainer.selectedNode;
	}

	protected void informOtherBeansOfSelect() {
		this.ldapMemberOfBean.setRoot(this.selectedNodeContainer.selectedNode);
		this.ldapMemberBean.setRoot(this.selectedNodeContainer.selectedNode);
		this.doTypeCallbacking();
	}

	@PostConstruct
	public void initRootNodes() {
		root = new ManualLeafHandlingTreeNode("root", new LdapObject(
				this.dnsName, this.getLdapTree().getBaseDN()), null);
		myRoot = new ManualLeafHandlingTreeNode("root", new LdapObject(
				this.dnsName, this.getLdapTree().getBaseDN()), root);
	}

	public void onNodeExpand(NodeExpandEvent event) {
		gahterChildrenOfTreeNode((ManualLeafHandlingTreeNode) event
				.getTreeNode());
	}

	public void onNodeSelect(NodeSelectEvent event) {
		this.setSelectedNode(event.getTreeNode());
	}

	public void refresh() {
		this.reset();
		this.getLdapTree().reset();
	}
	
	public void removeNodes(ManualLeafHandlingTreeNode node) {
		Iterator<TreeNode> i = node.getChildren().iterator();
		while (i.hasNext()) {
			i.next();
			i.remove();
		}
	}
	
	public void reset() {
		this.removeNodes((ManualLeafHandlingTreeNode) this.myRoot);
		this.myRoot.setExpanded(false);
	}

	public void resetSearch() {
		this.searchTerm = "";
		this.reset();
		gahterChildrenOfTreeNode((ManualLeafHandlingTreeNode)this.myRoot);
		this.myRoot.setExpanded(true);
	}
	
	public void search() {
		this.removeNodes((ManualLeafHandlingTreeNode) this.myRoot);
		final ManualLeafHandlingTreeNode parent = (ManualLeafHandlingTreeNode) this.myRoot;
		List<LdapObject> searchResults = this.getLdapTree().searchFor(
				this.searchTerm);
		for (final LdapObject ldapObject : searchResults) {
			ldapObject.isType(new ITypeCheckerCallback() {
				public void isContainer() {
					new ManualLeafHandlingTreeNode("container", ldapObject,
							parent);
				}

				public void isGroup() {
					new ManualLeafHandlingTreeNode("group", ldapObject, parent);
				}

				public void isLdapDomainController() {
					new ManualLeafHandlingTreeNode(
							"domainController", ldapObject, parent);
				}

				public void isLdapObject() {
					new ManualLeafHandlingTreeNode("ldapObject", ldapObject,
							parent);
				}

				public void isNestable() {

				}
				
				public void isUser() {
					new ManualLeafHandlingTreeNode("user", ldapObject, parent);
				}
				
				@Override
				public void isLdapDNSARecord() {
					new ManualLeafHandlingTreeNode(
							"ldapDNSARecord", ldapObject, parent);
				}
				
				@Override
				public void isLdapDNSCName() {
					new ManualLeafHandlingTreeNode(
							"ldapDNSCName", ldapObject, parent);
				}

				@Override
				public void isLdapDNSZone() {
					new ManualLeafHandlingTreeNode(
							"ldapDNSZone", ldapObject, parent);
				}

			});
		}
		this.myRoot.setExpanded(true);
	}

	public void setSearchTerm(String searchTerm) {
		this.searchTerm = searchTerm;
	}

	public void setSelectedNode(TreeNode selectedNode) {
		this.selectedNodeContainer.selectedNode = (ManualLeafHandlingTreeNode) selectedNode;

		this.informOtherBeansOfSelect();
	}

}